package wechat

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"time"

	"gitee.com/kvenli/go-sender/core"
	"gitee.com/kvenli/go-sender/wechat/message"
	"gitee.com/kvenli/go-sender/wechat/response"
)

const (
	Timeout = 5 * time.Second
	Webhook = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send"
)

type Bot struct {
	Key    string
	Client *http.Client
}

// NewBot 创建一个新的企业微信机器人实例。
func NewBot(key string) *Bot {
	return &Bot{
		Key:    key,
		Client: &http.Client{Timeout: Timeout},
	}
}

// Send 发送消息到企业微信机器人。
func (bot *Bot) Send(msg core.Message) (*core.Response, error) {
	var (
		data       []byte
		wechatResp *response.Response
		err        error
	)

	if msg.GetType() == "file" {
		fileMsg, ok := msg.(*message.File)
		if !ok {
			core.GetLogger().Printf("[%s] Send error: %s", msg.GetType(), "消息不是 wechat.message.File 类型")
			return nil, fmt.Errorf("%w: 消息不是 wechat.message.File 类型", core.ErrInvalidConfig)
		}
		// 上传文件并获取 media_id
		core.GetLogger().Printf("[%s] Uploading file: %s", msg.GetType(), fileMsg.FileName)
		if wechatResp, err = bot.upload(fileMsg.FileName); err != nil {
			core.GetLogger().Printf("[%s] File upload error: %s", msg.GetType(), err.Error())
			return nil, fmt.Errorf("%w: 文件上传失败: %v", core.ErrSendMessageFailed, err)
		}
		if wechatResp.Code != 0 {
			core.GetLogger().Printf("[%s] File upload failed. Code: %d, Message: %s", msg.GetType(), wechatResp.Code, wechatResp.Message)
			return &core.Response{Code: wechatResp.Code, Message: wechatResp.Message}, nil
		}
		fileMsg.FileBody.MediaId = wechatResp.MediaID
		core.GetLogger().Printf("[%s] File uploaded. MediaID: %s", msg.GetType(), wechatResp.MediaID)
		// 重新赋值 msg 为已包含 media_id 的文件消息
		msg = fileMsg
	}

	if data, err = json.Marshal(msg); err != nil {
		core.GetLogger().Printf("[%s] Send error: %s", msg.GetType(), err.Error())
		return nil, fmt.Errorf("%w: %v", core.ErrSendMessageFailed, err)
	}

	core.GetLogger().Printf("[%s] Sending message to WeChat: %s", msg.GetType(), string(data))
	if wechatResp, err = bot.send(data); err != nil {
		core.GetLogger().Printf("[%s] Send error: %s", msg.GetType(), err.Error())
		return nil, err
	}

	core.GetLogger().Printf("[%s] Message sent to WeChat. Response Code: %d, Message: %s", msg.GetType(), wechatResp.Code, wechatResp.Message)
	return &core.Response{Code: wechatResp.Code, Message: wechatResp.Message}, nil
}

// send 执行 HTTP 请求发送消息。
func (bot *Bot) send(data []byte) (*response.Response, error) {
	var (
		req *http.Request
		err error
	)
	if req, err = bot.buildSendRequest(data, http.Header{}); err != nil {
		return nil, fmt.Errorf("%w: %v", core.ErrNetworkFailure, err)
	}

	var resp *http.Response
	if resp, err = bot.Client.Do(req); err != nil {
		return nil, fmt.Errorf("%w: %v", core.ErrNetworkFailure, err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("%w: HTTP 错误码: %d", core.ErrNetworkFailure, resp.StatusCode)
	}

	var body []byte
	if body, err = io.ReadAll(resp.Body); err != nil {
		return nil, fmt.Errorf("%w: %v", core.ErrNetworkFailure, err)
	}

	wechatResp := new(response.Response)
	if err = json.Unmarshal(body, &wechatResp); err != nil {
		return nil, fmt.Errorf("%w: %v", core.ErrNetworkFailure, err)
	}
	return wechatResp, nil
}

// upload 上传文件到企业微信。
func (bot *Bot) upload(filename string) (*response.Response, error) {
	var (
		req *http.Request
		err error
	)
	if req, err = bot.buildUploadFileRequest(filename, http.Header{}); err != nil {
		return nil, fmt.Errorf("%w: %v", core.ErrNetworkFailure, err)
	}

	var resp *http.Response
	if resp, err = bot.Client.Do(req); err != nil {
		return nil, fmt.Errorf("%w: %v", core.ErrNetworkFailure, err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("%w: HTTP 错误码: %d", core.ErrNetworkFailure, resp.StatusCode)
	}

	var body []byte
	if body, err = io.ReadAll(resp.Body); err != nil {
		return nil, fmt.Errorf("%w: %v", core.ErrNetworkFailure, err)
	}

	wechatResp := new(response.Response)
	if err = json.Unmarshal(body, &wechatResp); err != nil {
		return nil, fmt.Errorf("%w: %v", core.ErrNetworkFailure, err)
	}
	return wechatResp, nil
}

// buildSendRequest 构建发送消息的 HTTP 请求。
func (bot *Bot) buildSendRequest(data []byte, header http.Header) (*http.Request, error) {
	var (
		url *url.URL
		err error
	)
	if url, err = url.Parse(Webhook); err != nil {
		return nil, err
	}
	query := url.Query()
	query.Set("key", bot.Key)
	url.RawQuery = query.Encode()
	// fmt.Println(url.String())

	var req *http.Request
	if req, err = http.NewRequest("POST", url.String(), bytes.NewReader(data)); err != nil {
		return nil, err
	}

	header.Set("Content-Type", "application/json;charset=utf-8")
	req.Header = header

	return req, nil
}

func (bot *Bot) buildUploadFileRequest(filename string, header http.Header) (*http.Request, error) {
	var (
		url *url.URL
		buf bytes.Buffer
		req *http.Request
		err error
	)
	multipartWriter := multipart.NewWriter(&buf)

	if url, err = url.Parse(Webhook); err != nil {
		return nil, err
	}

	// 创建文件表单字段
	fileWriter, err := multipartWriter.CreateFormFile("file", filepath.Base(filename))
	if err != nil {
		return nil, fmt.Errorf("%w: 写入缓冲区失败: %v", core.ErrNetworkFailure, err)
	}

	// 打开文件句柄
	fileinfo, err := os.Stat(filename)
	if err != nil {
		return nil, fmt.Errorf("%w: 打开文件失败: %v", core.ErrNetworkFailure, err)
	}
	file, err := os.Open(filename)
	if err != nil {
		return nil, fmt.Errorf("%w: 打开文件失败: %v", core.ErrNetworkFailure, err)
	}
	defer file.Close()

	// 拷贝文件内容到表单字段
	_, err = io.Copy(fileWriter, file)
	if err != nil {
		return nil, fmt.Errorf("%w: 拷贝文件内容失败: %v", core.ErrNetworkFailure, err)
	}
	multipartWriter.Close()

	url.Path = "cgi-bin/webhook/upload_media"
	query := url.Query()
	query.Set("key", bot.Key)
	query.Set("type", "file")
	//query.Set("debug", "1")
	url.RawQuery = query.Encode()

	if req, err = http.NewRequest("POST", url.String(), &buf); err != nil {
		return nil, err
	}
	header.Set("Content-Type", multipartWriter.FormDataContentType())
	header.Set("Content-Length", fmt.Sprint(fileinfo.Size()))
	req.Header = header
	return req, nil
}

// func postFile(filename string, targetUrl string) error {
// 	buf := &bytes.Buffer{}
// 	multipartWriter := multipart.NewWriter(buf)

// 	//关键的一步操作
// 	fileWriter, err := multipartWriter.CreateFormFile("file", filename)
// 	if err != nil {
// 		fmt.Println("error writing to buffer")
// 		return err
// 	}

// 	//打开文件句柄操作
// 	file, err := os.Open(filename)
// 	if err != nil {
// 		fmt.Println("error opening file")
// 		return err
// 	}
// 	defer file.Close()

// 	//iocopy
// 	_, err = io.Copy(fileWriter, file)
// 	if err != nil {
// 		return err
// 	}
// 	multipartWriter.Close()

// 	contentType := multipartWriter.FormDataContentType()

// 	resp, err := http.Post(targetUrl, contentType, buf)
// 	if err != nil {
// 		return err
// 	}
// 	defer resp.Body.Close()
// 	resp_body, err := ioutil.ReadAll(resp.Body)
// 	if err != nil {
// 		return err
// 	}
// 	fmt.Println(resp.Status)
// 	fmt.Println(string(resp_body))
// 	return nil
// }
